﻿Imports System
Imports System.Net
Imports System.Net.Mail
Imports System.Net.Mime
Imports System.Threading
Imports System.Net.Sockets
Imports dooll.config


Public Class SmtpSender
    Private mSmtpSetup As Account
    Private _mailFrom As String
    Private _displayName As String
    Private smtpMail As SmtpClient
    Private mException As Exception

#Region "属性 MailFrom | DisplayName | ErrMessage"

    Public ReadOnly Property ErrMessage() As String
        Get
            If mException Is Nothing Then
                Return String.Empty
            End If
            Return mException.Message
        End Get
    End Property

    Public Property MailFrom() As String
        Get
            Return _mailFrom
        End Get
        Set(ByVal value As String)
            _mailFrom = value
        End Set
    End Property

    Public Property DisplayName() As String
        Get
            Return _displayName
        End Get
        Set(ByVal value As String)
            _displayName = value
        End Set
    End Property
#End Region

    ''' <summary>
    ''' 加载邮件帐号
    ''' </summary>
    ''' <param name="Account">邮件帐号</param>
    ''' <remarks></remarks>
    Private Sub InitAccount(ByVal Account As Config.Account)
        smtpMail = New SmtpClient(Account.Server, Account.Port)
        smtpMail.Credentials = New NetworkCredential(Account.User, Account.Passowrd)
        smtpMail.EnableSsl = Account.EnableSsl
        If String.IsNullOrEmpty(Account.Mail) Then
            _mailFrom = Account.User
        Else
            _mailFrom = Account.Mail
        End If
        If String.IsNullOrEmpty(Account.DisplayName) Then
            _displayName = Account.User
        Else
            _displayName = Account.DisplayName
        End If
    End Sub


    Public Sub New()
        Dim mSmtpSetup As SmtpSetup = SmtpConfig.Load
        Dim Account As Config.Account = mSmtpSetup.Find(mSmtpSetup.DefaultAccount)
        InitAccount(Account)
        mSmtpSetup = Nothing
        Account = Nothing
    End Sub

    Public Sub New(ByVal account As Config.Account)
        InitAccount(account)
    End Sub

    Public Sub New(ByVal mailFrom As String, ByVal displayName As String, ByVal smtpServer As String, ByVal smtpPort As Integer, ByVal userName As String, ByVal password As String, ByVal smtpSsl As Boolean)
        Me._mailFrom = mailFrom
        Me._displayName = displayName
        smtpMail = New SmtpClient(smtpServer, smtpPort)
        smtpMail.Credentials = New NetworkCredential(userName, password)
        smtpMail.EnableSsl = smtpSsl
    End Sub
#Region "公用"

#Region "功能函数 Send"

    Public Function send(ByVal mailto As String) As Boolean
        Dim mailTos As String() = New String() {mailto}
        Dim attachments As String() = Nothing
        Dim bodyEncoding As System.Text.Encoding = System.Text.Encoding.UTF8
        Return send(mailTos, Nothing, Nothing, Nothing, Nothing, attachments, MailPriority.Normal, False, bodyEncoding)
    End Function

    Public Function Send(ByVal mailTo As String, ByVal mailSubject As String, ByVal mailBody As String, ByVal priority As MailPriority, ByVal isBodyHtml As Boolean) As Boolean
        Dim mailTos As String() = New String() {mailTo}
        Dim attachments As String() = Nothing
        Dim bodyEncoding As System.Text.Encoding = System.Text.Encoding.Default
        Return Send(mailTos, Nothing, Nothing, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding)
    End Function

    Public Function Send(ByVal mailTo As String, ByVal mailSubject As String, ByVal mailBody As String, ByVal attachments As String(), ByVal priority As MailPriority, ByVal isBodyHtml As Boolean, ByVal bodyEncoding As System.Text.Encoding) As Boolean
        Dim mailTos As String() = mailTo.Split(CChar(","))
        Return Send(mailTos, Nothing, Nothing, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding)
    End Function

    Public Function Send(ByVal mailTos As String(), ByVal mailCcs As String(), ByVal mailBccs As String(), ByVal mailSubject As String, ByVal mailBody As String, ByVal attachments As String(), ByVal priority As MailPriority, ByVal isBodyHtml As Boolean, ByVal bodyEncoding As System.Text.Encoding) As Boolean
        Return Send(Me._mailFrom, Me._displayName, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding)
    End Function

    Public Function Send(ByVal mailFrom As String, ByVal displayName As String, ByVal mailTos As String(), ByVal mailCcs As String(), ByVal mailBccs As String(), ByVal mailSubject As String, ByVal mailBody As String, ByVal attachments As String(), ByVal priority As MailPriority, ByVal isBodyHtml As Boolean, ByVal bodyEncoding As System.Text.Encoding) As Boolean
        Return SendMail(False, Nothing, mailFrom, displayName, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding)
    End Function

#End Region

    Public Sub SendAsync(ByVal userState As Object, ByVal mailTo As String, ByVal mailSubject As String, ByVal mailBody As String, ByVal priority As MailPriority, ByVal isBodyHtml As Boolean)
        Dim mailTos As String() = New String() {mailTo}
        Dim attachments As String() = Nothing
        Dim bodyEncoding As System.Text.Encoding = System.Text.Encoding.Default
        SendAsync(userState, mailTos, Nothing, Nothing, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding)
    End Sub

    Public Sub SendAsync(ByVal userState As Object, ByVal mailTo As String, ByVal mailSubject As String, ByVal mailBody As String, ByVal attachments As String(), ByVal priority As MailPriority, ByVal isBodyHtml As Boolean, ByVal bodyEncoding As System.Text.Encoding)
        Dim mailTos As String() = New String() {mailTo}
        SendAsync(userState, Me._mailFrom, Me._displayName, mailTos, Nothing, Nothing, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding)
    End Sub

    Public Sub SendAsync(ByVal userState As Object, ByVal mailFrom As String, ByVal displayName As String, ByVal mailTos As String(), ByVal mailCcs As String(), ByVal mailBccs As String(), ByVal mailSubject As String, ByVal mailBody As String, ByVal attachments As String(), ByVal priority As MailPriority, ByVal isBodyHtml As Boolean, ByVal bodyEncoding As System.Text.Encoding)
        SendMail(True, userState, mailFrom, displayName, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding)
    End Sub

    Public Sub SendAsync(ByVal userState As Object, ByVal mailTos As String(), ByVal mailCcs As String(), ByVal mailBccs As String(), ByVal mailSubject As String, ByVal mailBody As String, ByVal attachments As String(), ByVal priority As MailPriority, ByVal isBodyHtml As Boolean, ByVal bodyEncoding As System.Text.Encoding)
        SendMail(True, userState, Nothing, Nothing, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding)
    End Sub
#End Region

    REM "发送邮件"
    Private Function SendMail(ByVal isAsync As Boolean, ByVal userState As Object, ByVal mailFrom As String, ByVal displayName As String, ByVal mailTos As String(), ByVal mailCcs As String(), ByVal mailBccs As String(), ByVal mailSubject As String, ByVal mailBody As String, ByVal attachments As String(), ByVal priority As MailPriority, ByVal isBodyHtml As Boolean, ByVal bodyEncoding As System.Text.Encoding) As Boolean
        Dim mailSent As Boolean = False
        If String.IsNullOrEmpty(mailFrom) Then
            mailFrom = Me._mailFrom
        End If
        If String.IsNullOrEmpty(displayName) Then
            displayName = Me._displayName
        End If
        Dim Email As MailMessage = NewMailMessage(mailFrom, displayName, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding)
        AddHandler smtpMail.SendCompleted, AddressOf SendCompletedCallback
        Try
            If Not isAsync Then
                smtpMail.Send(Email)
            Else
                userState = IIf(IsNothing(userState), Guid.NewGuid(), userState)
                smtpMail.SendAsync(Email, userState)
            End If
            mailSent = True
        Catch ex As SmtpFailedRecipientsException
            mException = New Exception(ex.Message)
            mailSent = False
        Catch ex As Exception
            Dim l As New Logging.Log
            l.WriteException(ex)
            l = Nothing
            mException = New Exception(ex.Message)
            mailSent = False
        End Try
        Email.Dispose()
        Return mailSent
    End Function

    Private Function NewMailMessage(ByVal mailFrom As String, ByVal displayName As String, ByVal mailTos As String(), ByVal mailCcs As String(), ByVal mailBccs As String(), ByVal mailSubject As String, ByVal mailBody As String, ByVal attachments As String(), ByVal priority As MailPriority, ByVal isBodyHtml As Boolean, ByVal bodyEncoding As System.Text.Encoding) As MailMessage
        Dim emailMessage As MailMessage = New MailMessage
        If String.IsNullOrEmpty(mailFrom) Then
            mailFrom = Me._mailFrom
        End If
        If String.IsNullOrEmpty(displayName) Then
            displayName = Me._displayName
        End If
        Dim mailFromObject As MailAddress = New MailAddress(mailFrom, displayName)
        emailMessage.From = mailFromObject
        If Not (mailTos Is Nothing) Then
            For Each mailto As String In mailTos
                If Not String.IsNullOrEmpty(mailto) Then
                    Dim mailAddr As New MailAddress(mailto, "")
                    emailMessage.To.Add(mailAddr)
                End If
            Next
        End If
        If Not (mailCcs Is Nothing) Then
            For Each cc As String In mailCcs
                If Not String.IsNullOrEmpty(cc) Then
                    emailMessage.CC.Add(cc)
                End If
            Next
        End If
        If Not (mailBccs Is Nothing) Then
            For Each bcc As String In mailBccs
                If Not String.IsNullOrEmpty(bcc) Then
                    emailMessage.Bcc.Add(bcc)
                End If
            Next
        End If
        If Not (attachments Is Nothing) Then
            For Each file As String In attachments
                If Not String.IsNullOrEmpty(file) Then
                    Dim att As Attachment = New Attachment(file)
                    emailMessage.Attachments.Add(att)
                End If
            Next
        End If
        emailMessage.Subject = mailSubject
        emailMessage.Body = mailBody
        emailMessage.Priority = priority
        emailMessage.IsBodyHtml = isBodyHtml
        emailMessage.BodyEncoding = bodyEncoding
        Return emailMessage
    End Function

    Private Sub SendCompletedCallback(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
        Dim mailSent As Boolean = False
        Dim token As String = e.UserState.ToString
        If e.Cancelled Then
            Console.WriteLine("[{0}]   Send   canceled. ", token)
            mailSent = False
        End If
        If Not (e.Error Is Nothing) Then
            Console.WriteLine("[{0}]   {1} ", token, e.Error.ToString())
            mailSent = False
        Else
            Console.WriteLine("Message   sent. ")
            mailSent = False
        End If
        mailSent = True
    End Sub

    Protected Overrides Sub Finalize()
        mSmtpSetup = Nothing
        smtpMail = Nothing
        mException = Nothing
        MyBase.Finalize()
    End Sub
End Class

